package com.hacker.spider.wallhaven;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.LongAdder;

import com.hacker.spider.IHtmlHandler;
import com.hacker.spider.concurrent.ResultActuator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class WallHavenHandler implements IHtmlHandler<List<WallHavenImage>> {

  private static final LongAdder IMAGE_COUNT = new LongAdder();

  private static final LongAdder SUCCESS_COUNT = new LongAdder();

  private static final String PNG_EXTENSION = "png";

  private static final String BASE_URL = "https://w.wallhaven.cc/full";

  private static final String IMAGE_PREFIX = "wallhaven-";

  private static final String SEPARATOR = "/";

  private static final String FOLDER_PATH = "C:\\Users\\hackerW\\Desktop\\wallHaven\\";

  private final int pageNum;

  public WallHavenHandler(int pageNum) {
    this.pageNum = pageNum;
  }

  @Override public void handle(Document document) {
    getLogger().info("handle {}", pageNum);
    Element thumbs = document.getElementById("thumbs");
    if (pageNum != 1) {
      Elements pagNumSpan = thumbs.select(".thumb-listing-page-num");
      String pageNumStr = pagNumSpan.text();
      if (pageNum != Integer.parseInt(pageNumStr)) {
        getLogger().error("pageNum is not expect, expect {}, actually {}.", pageNum, pageNumStr);
        return;
      }
    }
    Element imageUl = thumbs.selectFirst("section > ul");
    Elements li = imageUl.getElementsByTag("li");
    List<WallHavenImage> images = new ArrayList<>(16);
    li.forEach(el -> {
      WallHavenImage wallHavenImage = new WallHavenImage();
      Element figure = el.selectFirst("figure");
      String imageName = figure.attr("data-wallpaper-id");
      Element image = figure.selectFirst("img");
      Element figDiv = figure.selectFirst("div.thumb-info");
      boolean isPngImage = false;
      if ((figDiv != null) && (Optional.ofNullable(figDiv.selectFirst("span[class=\"png\"]")).isPresent())) {
        isPngImage = true;
      }
      String previewPath = image.attr("data-src");
      if (!previewPath.contains(imageName)) {
        getLogger().error("data-src {} is not contains {}.", previewPath, imageName);
      }
      String extension = FilenameUtils.getExtension(previewPath);
      String defaultExtension = extension;
      if (isPngImage) {
        extension = PNG_EXTENSION;
      }
      wallHavenImage.setImageName(imageName + "." + extension);
      String temp = StringUtils.substringBeforeLast(previewPath, (SEPARATOR + imageName + "." + defaultExtension));
      String path = temp.substring(temp.lastIndexOf(SEPARATOR));
      String fullPath = BASE_URL + path + SEPARATOR + IMAGE_PREFIX + wallHavenImage.getImageName();
      wallHavenImage.setImagePath(fullPath);
      images.add(wallHavenImage);
    });
    IMAGE_COUNT.add(images.size());
    getLogger().debug("the {} page has image {},total {}.", pageNum, images.size(), IMAGE_COUNT.longValue());
    postHandle(images);
  }

  @Override public void postHandle(List<WallHavenImage> wallHavenImages) {
    wallHavenImages.parallelStream().forEach(this::addQueue);
  }

  private void addQueue(WallHavenImage imageTask) {
    ResultActuator.getInstance().addTask(buildDownloadTask(imageTask));
  }

  private Runnable buildDownloadTask(WallHavenImage imageTask) {
    return new Runnable() {
      @Override public void run() {
        try {
          Thread.sleep(1000);
          getLogger().debug("begin download page {} image {}", pageNum, imageTask.getImageName());
          File folder = new File(FOLDER_PATH);
          if (!folder.exists()) {
            folder.mkdir();
          }
          FileUtils
            .copyURLToFile(new URL(imageTask.getImagePath()), new File(folder, imageTask.getImageName()), 30000, 30000);
          SUCCESS_COUNT.increment();
          getLogger().debug("download page {} image {} success, total images {}, total success {} images.", pageNum,
            imageTask.getImageName(), IMAGE_COUNT.longValue(), SUCCESS_COUNT.longValue());
        } catch (Throwable e) {
          getLogger().error("{} download image {} fail, reason:{}. retry", Thread.currentThread().getName(),
            imageTask.getImageName(), e.getMessage());
          try {
            Thread.sleep(3000);
          } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
          }
          ResultActuator.getInstance().rejectRetry(this);
        }
      }
    };
  }
}
